import cv2 as cv
import numpy as np
import math


path = "D:\\download\\450d23eaec784b8d19f413014b020f3b.jpeg"
image = cv.imread(path)
image1 = cv.imread(path)
image2 = cv.cvtColor(image, cv.COLOR_BGR2HSV)


def noise(img):
    h = img.shape[0]
    w = img.shape[1]
    img1 = img.copy()
    sp = h * w   # 计算图像像素点个数
    count = int(sp / 1000)   # 计算图像椒盐噪声点个数
    for i in range(count):
        rand_x = np.random.randint(1, h-1)   # 生成一个 1 至 h-1 之间的随机整数
        rand_y = np.random.randint(1, w-1)   # 生成一个 1 至 w-1 之间的随机整数
        if np.random.random() <= 0.5:   # np.random.random()生成一个 0 至 1 之间的浮点数
            img1[rand_x, rand_y] = 0
        else:
            img1[rand_x, rand_y] = 255
    return img1


# 均值滤波
def avgFilter():
    img_avg = cv.blur(image, (3, 3))
    cv.namedWindow("avg_filter_use_api", cv.WINDOW_AUTOSIZE)
    cv.imshow("avg_filter_use_api", img_avg)
    sp = image.shape
    w = sp[0]
    h = sp[1]
    for x in range(1, w - 1):
        for y in range(1, h - 1):
            b = image[x-1, y-1, 0] / 9 + image[x-1, y, 0] / 9 + image[x-1, y+1, 0] / 9 + image[x, y-1, 0] / 9 \
                + image[x, y, 0] / 9 + image[x, y+1, 0] / 9 + image[x+1, y-1, 0] / 9 + image[x+1, y, 0] / 9 \
                + image[x+1, y+1, 0] / 9
            g = image[x-1, y-1, 1] / 9 + image[x-1, y, 1] / 9 + image[x-1, y+1, 1] / 9 + image[x, y-1, 1] / 9 \
                + image[x, y, 1] / 9 + image[x, y+1, 1] / 9 + image[x+1, y-1, 1] / 9 + image[x+1, y, 1] / 9 \
                + image[x+1, y+1, 1] / 9
            r = image[x-1, y-1, 2] / 9 + image[x-1, y, 2] / 9 + image[x-1, y+1, 2] / 9 + image[x, y-1, 2] / 9 \
                + image[x, y, 2] / 9 + image[x, y+1, 2] / 9 + image[x+1, y-1, 2] / 9 + image[x+1, y, 2] / 9 \
                + image[x+1, y+1, 2] / 9
            image[x, y] = (b, g, r)
    cv.namedWindow("my_avg_filter", cv.WINDOW_AUTOSIZE)
    cv.imshow("my_avg_filter", image)
    cv.waitKey(0)
    cv.destroyAllWindows()


# 中值滤波
def medianFilter():
    img_median = cv.medianBlur(image, 3)
    cv.namedWindow("median_filter_use_api", cv.WINDOW_AUTOSIZE)
    cv.imshow("median_filter_use_api", img_median)
    sp = image.shape
    w = sp[0]
    h = sp[1]
    for x in range(1, w - 1):
        for y in range(1, h - 1):
            b = []
            g = []
            r = []
            for x1 in range(-1, 2):
                for y1 in range(-1, 2):
                    b.append(int(image[x+x1, y+y1][0]))
                    g.append(int(image[x+x1, y+y1][1]))
                    r.append(int(image[x+x1, y+y1][2]))
            b.sort()
            g.sort()
            r.sort()
            image[x, y] = (b[4], g[4], r[4])
    cv.namedWindow("my_median_filter", cv.WINDOW_AUTOSIZE)
    cv.imshow("my_median_filter", image)
    cv.waitKey(0)
    cv.destroyAllWindows()


def gaussianFilter():
    img_gaussian = cv.GaussianBlur(image, (5, 5), 1)
    cv.namedWindow("gaussian_filter_use_api", cv.WINDOW_AUTOSIZE)
    cv.imshow("gaussian_filter_use_api", img_gaussian)
    sp = image.shape
    w = sp[0]
    h = sp[1]
    sigma = 1.0
    k = 2
    pi = math.pi
    for x in range(2, w - 2):
        for y in range(2, h - 2):
            sum = 0
            b = 0
            r = 0
            g = 0
            # 高斯模板
            window = [[], [], [], [], []]
            # 窗口模板大小为5 * 5, k = 2
            for x1 in range(5):
                pow_res1 = math.pow(x1 - k - 1, 2)
                for y1 in range(5):
                    pow_res2 = math.pow(y1 - k - 1, 2)
                    val = math.exp(-(pow_res1 + pow_res2) / (2 * math.pow(sigma, 2)))
                    val /= (2 * pi * sigma)
                    window[x1].append(val)
                    sum = sum + val
            # 归一化处理
            for i in range(5):
                for j in range(5):
                    window[i][j] /= sum
            for x1 in range(5):
                for y1 in range(5):
                    b += float(image[x+x1-2, y+y1-2][0]) * window[x1][y1]
                    g += float(image[x+x1-2, y+y1-2][1]) * window[x1][y1]
                    r += float(image[x+x1-2, y+y1-2][2]) * window[x1][y1]
            image[x, y] = (b, g, r)
    cv.namedWindow("my_gaussian_filter", cv.WINDOW_AUTOSIZE)
    cv.imshow("my_gaussian_filter", image)
    cv.waitKey(0)
    cv.destroyAllWindows()


def bilateralFilter():
    img_bilateral = cv.bilateralFilter(image, 5, 75, 75)
    cv.namedWindow("bilateral_filter_use_api", cv.WINDOW_AUTOSIZE)
    cv.imshow("bilateral_filter_use_api", img_bilateral)
    sp = image.shape
    w = sp[0]
    h = sp[1]
    sigma_d = 75    # 定义域核sigma
    sigma_r = 75    # 值域核sigma
    for x in range(2, w - 2):
        for y in range(2, h - 2):
            sum = 0
            b = 0
            r = 0
            g = 0
            window = [[], [], [], [], []]
            for x1 in range(5):
                for y1 in range(5):
                    db = int(image[x+x1-2, y+y1-2][0]) - int(image[x, y][0])
                    dr = int(image[x+x1-2, y+y1-2][1]) - int(image[x, y][1])
                    dg = int(image[x+x1-2, y+y1-2][2]) - int(image[x, y][2])
                    # 计算定义域核
                    definitionCore = math.exp(-((x1-2)*(x1-2)+(y1-2)*(y1-2))/2/sigma_d/sigma_d)
                    # 计算值域核
                    rangeCore = math.exp(-(db*db+dr*dr+dg*dg)/2/sigma_r/sigma_r)
                    # 权重系数为两者乘积
                    val = definitionCore * rangeCore
                    window[x1].append(val)
                    sum = sum + val
            # 归一化处理
            for i in range(5):
                for j in range(5):
                    window[i][j] /= sum
            for x1 in range(5):
                for y1 in range(5):
                    b += float(image[x+x1-2, y+y1-2][0]) * window[x1][y1]
                    g += float(image[x+x1-2, y+y1-2][1]) * window[x1][y1]
                    r += float(image[x+x1-2, y+y1-2][2]) * window[x1][y1]
            image[x, y] = (b, g, r)
    cv.namedWindow("my_bilateral_filter", cv.WINDOW_AUTOSIZE)
    cv.imshow("my_bilateral_filter", image)
    cv.waitKey(0)
    cv.destroyAllWindows()


if __name__ == '__main__':
    image = noise(image)
    cv.namedWindow("old", cv.WINDOW_AUTOSIZE)
    cv.imshow("old", image)
    # avgFilter()
    # medianFilter()
    # gaussianFilter()
    bilateralFilter()
